import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import cors from 'cors';
import express from 'express';
interface Result {
  type: string;
  text: string;
}
interface McpResult {
  content: Result[];
}
// 日志帮助函数
const logClient = (message: string, ...args: any[]) => console.log(`[CLIENT] ${message}`, ...args);
const errorClient = (message: string, ...args: any[]) =>
  console.error(`[CLIENT] ${message}`, ...args);

const MCP_SERVER_URL = 'http://localhost:4000/mcp';

// 注意：内存存储仅用于开发。服务器重启后数据会丢失。
// 在生产环境中，应考虑使用持久化存储，如 Redis 或数据库。
const sessionStore = new Map<string, { history: any[] }>();

function createMcpClient() {
  const transport = new StreamableHTTPClientTransport(new URL(MCP_SERVER_URL));
  const client = new Client({
    name: 'example-node-client',
    version: '1.0.0',
  });
  return { client, transport };
}

// 创建一个全局复用的 client 和 transport 实例
const { client, transport } = createMcpClient();

/**
 * 调用 MCP 服务的主逻辑
 * @param text用户的输入文本
 * @param context 会话上下文，包含历史记录
 * @returns 来自 MCP 工具调用的结果
 */
export async function askMcp(text: string, sessionId: string) {
  const mcpResult = await client.callTool({
    name: 'parse_intent',
    arguments: { text, sessionId },
  });
  logClient('🚀 ~ client.ts:25 ~ askMcp ~ mcpResult:', mcpResult);

  return mcpResult;
}

/**
 * 配置并启动 Express 服务器
 * @param port 监听的端口，默认为 5000
 */
export async function startClient(port = 5000) {
  const app = express();

  // --- 优化的 CORS 配置 ---
  // 这种方式比简单的 app.use(cors()) 更安全。
  // 它明确地告诉浏览器，只允许来自你的前端应用的请求。
  const corsOptions: cors.CorsOptions = {
    // 替换为你的前端应用的实际源地址
    origin: '*',
    // 允许你的前端会使用到的 HTTP 方法
    methods: 'POST, GET, OPTIONS',
    // 允许必要的请求头
    allowedHeaders: 'Content-Type, Authorization',
    // 如果你的前端需要发送凭据（例如 cookie、认证令牌），这个选项至关重要
    credentials: true,
  };

  // 对于复杂请求（例如带 JSON 内容的 POST 请求），浏览器会先发送一个 "预检" OPTIONS 请求。
  // 这行代码就是用来处理这些预检请求的。
  app.options('*', cors(corsOptions));

  // 将 CORS 配置应用到所有其他请求
  app.use(cors(corsOptions));
  // --- CORS 配置结束 ---

  // 中间件，用于解析传入的 JSON 请求体
  app.use(express.json());

  try {
    // 在服务器启动时连接一次 MCP 服务
    await client.connect(transport);
    logClient('🔗 已成功连接到 MCP 服务器。');
  } catch (err) {
    errorClient('❌ 连接 MCP 服务器失败:', err);
    // 如果核心服务无法连接，则退出进程
    process.exit(1);
  }

  app.post('/api/ask', async (req, res) => {
    let { text } = req.body;
    let sessionId: string = '';
    if (req.headers['mcp-session-id']) {
      sessionId = req.headers['mcp-session-id'] as string;
    }

    if (!text) {
      return res.status(400).json({ error: '必须提供 "text" 字段。' });
    }

    if (!sessionId) return res.status(400).json({ sessionId, error: `请带上sessionId` });

    // 获取或初始化会话历史
    let sessionData = sessionStore.get(sessionId);
    if (!sessionData) {
      sessionData = { history: [] };
      sessionStore.set(sessionId, sessionData);
    }

    // 在调用 AI 之前，将用户的新消息添加到历史记录中
    sessionData.history.push({ role: 'user', content: text });

    try {
      const result = (await askMcp(text, sessionId)) as McpResult;

      // 将助手的回复也添加到历史记录中
      sessionData.history.push({ role: 'assistant', content: result });
      const contents = result.content.reduce((pre: string, cur) => {
        return pre + cur.text;
      }, '');
      res.json({ sessionId, text: contents });
    } catch (err) {
      errorClient(`处理会话 ${sessionId} 的 /api/ask 请求时出错:`, err);
      // 提供一个更健壮的错误信息
      const errorMessage = err instanceof Error ? err.message : String(err);
      res.status(500).json({ sessionId, error: `发生内部服务器错误: ${errorMessage}` });
    }
  });

  return new Promise<void>((resolve) => {
    app.listen(port, () => {
      logClient(`✅ 正在监听 POST 请求: http://localhost:${port}/api/ask`);
      resolve();
    });
  });
}
